package com.dragon.service.impl.java;

import cn.hutool.core.io.FileUtil;
import com.dragon.pojo.ExecuteMessage;
import com.dragon.service.impl.CommonServiceImpl;
import com.dragon.utils.GetClassNameUtils;
import com.dragon.utils.ProcessUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

@Slf4j
@Component("java")
public class JavaServiceImpl extends CommonServiceImpl {
    @Override
    public File saveCodeToFile(String code) {
        final String GLOBAL_CODE_DIR_NAME = "codeTemp";
        String className = GetClassNameUtils.getClassNameUtils(code);
        log.info("文件的类名:{}",className);
        final String GLOBAL_JAVA_CLASS_NAME = className + ".java";
        // 获取当前运行程序的工作目录
        String userDir = System.getProperty("user.dir");
        // 构建全局代码存储目录的完整路径(userDir + 文件分隔符 + 全局目录名)
        String globalCodePathName = userDir + File.separator + GLOBAL_CODE_DIR_NAME;
        log.info("globalCodePathName:{}",globalCodePathName);
        // 如果目录不存在则创建
        if(!FileUtil.exist(globalCodePathName)){
            FileUtil.mkdir(globalCodePathName);
        }
        // 使用UUID生成目录名
        String userCodeParentPath = globalCodePathName + File.separator + UUID.randomUUID();
        // 构造具体的java文件路径
        String userCodePath = userCodeParentPath + File.separator + GLOBAL_JAVA_CLASS_NAME;

        return FileUtil.writeString(code, userCodePath, StandardCharsets.UTF_8);
    }

    @Override
    public ExecuteMessage compileFile(File userCodeFile) {
        // 构造编译命令
        String compileCmd = String.format("javac -encoding utf-8 %s", userCodeFile.getAbsolutePath());
        log.info("compileCmd:{}",compileCmd);
        try{
            // 执行系统命令 javac 进行编译
            Process compileProcess = Runtime.getRuntime().exec(compileCmd);
            // 运行并监听编译过程
            ExecuteMessage executeMessage = ProcessUtils.runProcessAndGetMessage(compileProcess, "编译",null,10000L);
            // 判断编译是否成功
            if(executeMessage.getExitValue() != 0){
                // 如果编译失败，删除临时文件
                boolean del = FileUtil.del(userCodeFile.getParentFile());
                log.info("编译失败，删除:{}",del ? "成功" : "失败");
            }
            log.info("compileMessage:{}",executeMessage);
            return executeMessage;
        } catch (Exception e) {
            throw new RuntimeException(e);

        }

    }

    @Override
    public List<ExecuteMessage> runFile(File userCodeFile, List<String> inputList,long timeLimit) {
//        final long TIME_OUT = 5000L;
        String userCodeParentPath = userCodeFile.getParentFile().getAbsolutePath();

        // 获取当前JVM的类路径
        String appClassPath = System.getProperty("java.class.path");
        // 获取当前系统的路径分隔符 (Windows: ; Linux: :)
        String pathSeparator = File.pathSeparator;
        // 构造包含主项目类路径和用户代码路径的完整、跨平台的 classpath
        String classPath = String.join(pathSeparator, appClassPath, userCodeParentPath);

        List<ExecuteMessage> executeMessagesList = new ArrayList<>();

        // 从 File 对象获取类名
        String userCodeFileName = userCodeFile.getName();
        // 从 Main.java 中提取出 Main
        String className = userCodeFileName.substring(0, userCodeFileName.lastIndexOf(".java"));

        for (String inputArgs : inputList) {
            // -Xmx256m: 设置 JVM 最大堆内存为 256MB
            // -Dfile.encoding=UTF-8: 强制使用 UTF-8 编码
            // 使用我们新的、动态的、跨平台的 classpath
            // 调用 MemoryTrackingExecutor 包装器，并将真正的类名 Main 和参数传给它
            List<String> command = new ArrayList<>();
            command.add("java");
            command.add("-Xmx256m");
            command.add("-Dfile.encoding=UTF-8");
            command.add("-cp");
            command.add(classPath); // 当使用数组时，路径中的空格会被正确处理，无需额外引号
            command.add("com.dragon.executor.CodeExecutor");
            command.add("com.dragon.executor.MemoryTrackingWrapper");
            command.add(className);
            command.add(String.valueOf(timeLimit));

            try{
                Process runProcess = Runtime.getRuntime().exec(command.toArray(new String[0]));

                log.info("程序输入:{}",inputArgs);
                ExecuteMessage executeMessage = ProcessUtils.runProcessAndGetMessage(runProcess, "运行",inputArgs + "\n",timeLimit + 2000L);
                log.info("输出结果: {}", executeMessage.getMessage());
                log.info("executeMessage:{}",executeMessage);
                executeMessagesList.add(executeMessage);
            } catch (IOException e) {
                log.error("执行用户代码时出错", e);
                throw new RuntimeException(e);
            }
        }
        return executeMessagesList;
    }

}
